package math.region;

import math.vec3;

public class AABB3 implements Volume3
{
    
    public static AABB3 interp(
            AABB3 aA, 
            AABB3 aB, 
            double aInterpTerm)
    {
        vec3 interpMin = vec3.lerp(aA.mMin, aB.mMin, aInterpTerm);
        vec3 interpMax = vec3.lerp(aA.mMax, aB.mMax, aInterpTerm);
        return new AABB3(interpMin, interpMax);
    }
    
    
    /** Euclidean minimum location */
    public vec3 mMin;
    
    /** Euclidean maximum location */
    public vec3 mMax;
    
    
    public AABB3()
    {
        this.mMin = new vec3();
        this.mMax = new vec3();
    }
    
    public AABB3(
            vec3 aMin, 
            vec3 aMax)
    {
        this();
        this.set(aMin, aMax);
    }
    
    
    public final void set(
            vec3 aMin, 
            vec3 aMax)
    {
        this.mMin.set(aMin);
        this.mMax.set(aMax);
    }
    
    public final void set(AABB3 aOther)
    {
        this.set(aOther.mMin, aOther.mMax);
    }
    
    public void extendToContain(vec3 aPoint)
    {
        if (aPoint.x < this.mMin.x)
        {
            this.mMin.x = aPoint.x;
        }
        else if (aPoint.x > this.mMax.x)
        {
            this.mMax.x = aPoint.x;
        }
        if (aPoint.y < this.mMin.y)
        {
            this.mMin.y = aPoint.y;
        }
        else if (aPoint.y > this.mMax.y)
        {
            this.mMax.y = aPoint.y;
        }
        if (aPoint.z < this.mMin.z)
        {
            this.mMin.z = aPoint.z;
        }
        else if (aPoint.z > this.mMax.z)
        {
            this.mMax.z = aPoint.z;
        }
    }
    
    public void extendToContain(AABB3 box)
    {
        this.extendToContain(box.mMin);
        this.extendToContain(box.mMax);
    }
    
    public void transl(vec3 aTransl)
    {
        this.mMin.add(aTransl);
        this.mMax.add(aTransl);
    }
    
    
    public boolean overlaps(AABB3 aOther)
    {
        return (
            (this.mMin.x < aOther.mMax.x && this.mMax.x > aOther.mMin.x) && 
            (this.mMin.y < aOther.mMax.y && this.mMax.y > aOther.mMin.y) && 
            (this.mMin.z < aOther.mMax.z && this.mMax.z > aOther.mMin.z)
        );
    }
    
    public boolean insideVol(vec3 aPoint)
    {
        return (
            (aPoint.x >= this.mMin.x && aPoint.x <= this.mMax.x) && 
            (aPoint.y >= this.mMin.y && aPoint.y <= this.mMax.y) && 
            (aPoint.z >= this.mMin.z && aPoint.z <= this.mMax.z)
        );
    }
    
    
    public vec3 size()
    {
        return new vec3(
            this.mMax.x - this.mMin.x, 
            this.mMax.y - this.mMin.y, 
            this.mMax.z - this.mMin.z
        );
    }
    
    
    public vec3[] extrema()
    {
        vec3[] extrema = new vec3[8];
        extrema[0] = new vec3(this.mMin.x, this.mMin.y, this.mMin.z);
        extrema[1] = new vec3(this.mMin.x, this.mMin.y, this.mMax.z);
        extrema[2] = new vec3(this.mMin.x, this.mMax.y, this.mMin.z);
        extrema[3] = new vec3(this.mMin.x, this.mMax.y, this.mMax.z);
        extrema[4] = new vec3(this.mMax.x, this.mMin.y, this.mMin.z);
        extrema[5] = new vec3(this.mMax.x, this.mMin.y, this.mMax.z);
        extrema[6] = new vec3(this.mMax.x, this.mMax.y, this.mMin.z);
        extrema[7] = new vec3(this.mMax.x, this.mMax.y, this.mMax.z);
        return extrema;
    }
    
    
    public AABB3 copy()
    {
        AABB3 copy = new AABB3();
        copy.set(this);
        return copy;
    }
    
    
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append("AABB3\n   Min: ");
        sb.append(this.mMin);
        sb.append("\n   Max: ");
        sb.append(this.mMax);
        return sb.toString();
    }
    
}
